/**************************************************************************************************
	$Header: /pub/cvsroot/mydns/src/lib/sql.c,v 1.10 2002/12/08 07:49:43 bboy Exp $
	Don Moore <bboy@bboy.net>
	Copyright (c) 2002 Intercosmos Media Group, Inc.
**************************************************************************************************/

#include "mydns.h"

SQL *sql;															/* Global SQL connection information */


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_OPEN
	Connect to the database.  Errors fatal.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
sql_open(u_char *user, u_char *password, u_char *host, u_char *database)
{
	u_char *portp = NULL;
	unsigned int port = 0;

	if (host && (portp = strchr(host, ':')))
	{
		port = atoi(portp + 1);
		*portp = '\0';
	}

#if USE_PGSQL
	sql = PQsetdbLogin(host, portp, NULL, NULL, database, user, password);
	if (PQstatus(sql) == CONNECTION_BAD)
		ErrSQL(sql, _("Error connecting to PostgreSQL server at %s"), host);
#else
	sql = NULL;
	if (!(sql = mysql_init(NULL)))
		Err(_("Unable to allocate MySQL data structure"));
#if MYSQL_VERSION_ID > 32349
	mysql_options(sql, MYSQL_READ_DEFAULT_GROUP, "client");
#endif
	if (!(mysql_real_connect(sql, host, user, password, database, port, NULL, 0)))
		ErrSQL(sql, _("Error connecting to MySQL server at %s"), host);
#endif

	if (portp)
		*portp = ':';
}
/*--- sql_open() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_ISTABLE
	Returns 1 if the specified table exists in the current database, or 0 if it does not.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int
sql_istable(SQL *sql, const char *tablename)
{
	unsigned char *xtablename;
#if !USE_PGSQL
	SQL_RES *res;
#endif
	int rv = 0;

	if (!(xtablename = calloc(strlen(tablename) * 2 + 1, sizeof(unsigned char))))
		Err(_("out of memory"));
	sql_escstr(sql, xtablename, (u_char *)tablename, strlen(tablename));

#if USE_PGSQL
	if (sql_count(sql, "SELECT COUNT(*) FROM pg_class WHERE relkind='r' AND relname='%s'", xtablename) > 0)
		rv = 1;
#else
	if ((res = sql_queryf(sql, "SHOW TABLES LIKE '%s'", xtablename)))
	{
		if (sql_num_rows(res) > 0)
			rv = 1;
		sql_free(res);
	}
#endif

	free(xtablename);
	return (rv);
}
/*--- sql_istable() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_ISCOLUMN
	Returns 1 if the specified column exists in the current database, or 0 if it does not.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int
sql_iscolumn(SQL *sql, const char *tablename, const char *columnname)
{
	unsigned char *xtablename, *xcolumnname;
#if !USE_PGSQL
	SQL_RES *res;
#endif
	int rv = 0;

	if (!(xtablename = calloc(strlen(tablename) * 2 + 1, sizeof(unsigned char))))
		Err(_("out of memory"));
	if (!(xcolumnname = calloc(strlen(columnname) * 2 + 1, sizeof(unsigned char))))
		Err(_("out of memory"));
	sql_escstr(sql, xtablename, (u_char *)tablename, strlen(tablename));
	sql_escstr(sql, xcolumnname, (u_char *)columnname, strlen(columnname));

#if USE_PGSQL
	if (sql_count(sql,
			"SELECT COUNT(*)"
			" FROM pg_class,pg_attribute"
			" WHERE relkind='r'"
			" AND relname='%s'"
			" AND attrelid=oid"
			" AND attname='%s'", xtablename, xcolumnname) > 0)
		rv = 1;
#else
	if ((res = sql_queryf(sql, "SHOW COLUMNS FROM %s LIKE '%s'", xtablename, xcolumnname)))
	{
		if (sql_num_rows(res) > 0)
			rv = 1;
		sql_free(res);
	}
#endif

	free(xtablename);
	free(xcolumnname);
	return (rv);
}
/*--- sql_iscolumn() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	_SQL_CLOSE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
_sql_close(SQL *sql)
{
#if USE_PGSQL
	PQfinish(sql);
#else
	mysql_close(sql);
#endif
}
/*--- _sql_close() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_QUERY
	Returns a query's result, or NULL on error.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
SQL_RES *
sql_query(SQL *sql, const u_char *query, size_t querylen)
{
	SQL_RES *res = NULL;

#if USE_PGSQL
	{
		ExecStatusType q_rv = PGRES_COMMAND_OK;
		PGresult *result = NULL;

		result = PQexec(sql, query);
		q_rv = PQresultStatus(result);

		if (q_rv == PGRES_TUPLES_OK)
		{
			if (!(res = malloc(sizeof(SQL_RES))))
			{
				PQclear(result);
				return (NULL);
			}
			res->result = result;
			res->tuples = PQntuples(result);
			res->fields = PQnfields(result);
			res->current_tuple = 0;
			if (!(res->current_row = malloc(res->fields * sizeof(unsigned char *))))
			{
				free(res);
				PQclear(result);
				return (NULL);
			}
		}
		else if (q_rv == PGRES_COMMAND_OK)
		{
			PQclear(result);
			return (NULL);
		}
		else
		{
			WarnSQL(sql, _("%s: error during query"), PQresStatus(PQresultStatus(result)));
			PQclear(result);
			return (NULL);
		}
	}
#else
	if (mysql_real_query(sql, query, querylen) || !(res = mysql_store_result(sql)))
		return (NULL);
#endif

	return (res);
}
/*--- sql_query() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_QUERYF
	Like sql_query, but accepts varargs format.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
SQL_RES *
sql_queryf(SQL *sql, const char *fmt, ...)
{
	va_list ap;
	char buf[DNS_QUERYBUFSIZ];
	size_t buflen;

	va_start(ap, fmt);
	buflen = vsnprintf(buf, sizeof(buf), fmt, ap);
	va_end(ap);

	return sql_query(sql, buf, buflen);
}
/*--- sql_queryf() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_COUNT
	Provided a statement like "SELECT COUNT(*)..." returns the count returned, or -1 if an error
	occurred.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
long
sql_count(SQL *sql, const char *fmt, ...)
{
	va_list ap;
	char buf[DNS_QUERYBUFSIZ];
	size_t buflen;
	SQL_RES *res = NULL;
	long rv = 0;

	va_start(ap, fmt);
	buflen = vsnprintf(buf, sizeof(buf), fmt, ap);
	va_end(ap);

	if (!(res = sql_query(sql, buf, buflen)))
		return (-1);
	if (sql_num_rows(res))
#if USE_PGSQL
		rv = atol(PQgetvalue(res->result, 0, 0));
#else
	{
		MYSQL_ROW row;

		if ((row = mysql_fetch_row(res)))
			rv = atol(row[0]);
	}
#endif
	sql_free(res);
	return (rv);
}
/*--- sql_count() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_NUM_ROWS
	Returns the number of rows in a result set.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
long
sql_num_rows(SQL_RES *res)
{
#if USE_PGSQL
	return res->tuples;
#else
	return mysql_num_rows(res);
#endif
}
/*--- sql_num_rows() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_GETROW
	Returns the next row from the result, or NULL if no more rows exist.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
SQL_ROW
sql_getrow(SQL_RES *res)
{
#if USE_PGSQL
	register int n;

	if (res->current_tuple >= res->tuples)
		return (NULL);
	for (n = 0; n < res->fields; n++)
		res->current_row[n] = PQgetvalue(res->result, res->current_tuple, n);
	res->current_tuple++;
	return (res->current_row);
#else
	return mysql_fetch_row(res);
#endif
}
/*--- sql_getrow() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_ESCSTR
	Escapes a string to make it suitable for an SQL query.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
sql_escstr(SQL *sql, unsigned char *dest, unsigned char *src, size_t srclen)
{
#if USE_PGSQL
	PQescapeString(dest, src, srclen);
#else
	mysql_real_escape_string(sql, dest, src, srclen);
#endif
}
/*--- sql_escstr() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	_SQL_FREE
	Free an SQL result.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
_sql_free(SQL_RES *res)
{
#if USE_PGSQL
	free(res->current_row);
	PQclear(res->result);
	free(res);
#else
	mysql_free_result(res);
#endif
}
/*--- _sql_free() -------------------------------------------------------------------------------*/

/* vi:set ts=3: */
